using System;
using System.Collections.Generic;
using System.Reflection;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using AZROLESLib;
using AzManContrib.MVC.Html.Behaviors;
using System.Web.Mvc.Html;

namespace AzManContrib.MVC.Html
{
    
    public static class LinkExtensions
    {

        /* 
         * Non generic with operation by name
         */
        public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, object routeValues, string operation)
        {
            return ActionLink(htmlHelper, linkText, actionName, routeValues, AzMan.Application.Operations.FindByName(operation));
        }

        public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, object routeValues, object htmlAttributes, string operation)
        {
            return ActionLink(htmlHelper, linkText, actionName, routeValues, htmlAttributes, AzMan.Application.Operations.FindByName(operation));
        }

        public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, RouteValueDictionary routeValues, string operation)
        {
            return ActionLink(htmlHelper, linkText, actionName, routeValues, AzMan.Application.Operations.FindByName(operation));
        }

        public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes, string operation)
        {
            return ActionLink(htmlHelper, linkText, actionName, routeValues, htmlAttributes, AzMan.Application.Operations.FindByName(operation));
        }

        public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName, string operation)
        {
            return ActionLink(htmlHelper, linkText, actionName, controllerName, AzMan.Application.Operations.FindByName(operation));
        }

        public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName, object routeValues, object htmlAttributes, string operation)
        {
            return ActionLink(htmlHelper, linkText, actionName, controllerName, routeValues, htmlAttributes, AzMan.Application.Operations.FindByName(operation));
        }

        public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName, string protocol, string hostName, string fragment, object routeValues, object htmlAttributes, string operation)
        {
            return ActionLink(htmlHelper, linkText, actionName, controllerName, protocol, hostName, fragment, routeValues, htmlAttributes, AzMan.Application.Operations.FindByName(operation));
        }

        public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes, string operation)
        {
            return ActionLink(htmlHelper, linkText, actionName, controllerName, routeValues, htmlAttributes, AzMan.Application.Operations.FindByName(operation));
        }

        public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName, string protocol, string hostName, string fragment, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes, string operation)
        {
            return ActionLink(htmlHelper, linkText, actionName, controllerName, protocol, hostName, fragment, routeValues, htmlAttributes, AzMan.Application.Operations.FindByName(operation));
        }

        /* 
         * Non generic method, thus using AzMan.Defaults.UI.DenyiedBehavior 
         */
        public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, IAzOperation operation)
        {
            Func<HtmlHelper, string, string, IAzOperation, MvcHtmlString> genMethod = ActionLink<HiddenUIBehavior>;
            MethodInfo method = genMethod.Method.GetGenericMethodDefinition();
            MethodInfo generic = method.MakeGenericMethod(new []{AzMan.Defaults.UI.DenyiedBehavior}) ;
            return generic.Invoke(htmlHelper, new object[] { htmlHelper, linkText, actionName, operation }) as MvcHtmlString;
        }

        public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, object routeValues, IAzOperation operation)
        {
            Func<HtmlHelper, string, string, object, IAzOperation, MvcHtmlString> genMethod = ActionLink<HiddenUIBehavior>;
            MethodInfo method = genMethod.Method.GetGenericMethodDefinition();
            MethodInfo generic = method.MakeGenericMethod(new []{AzMan.Defaults.UI.DenyiedBehavior}) ;
            return generic.Invoke(htmlHelper, new [] { htmlHelper, linkText, actionName, routeValues, operation }) as MvcHtmlString;
        }

        public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, object routeValues, object htmlAttributes, IAzOperation operation)
        {
            Func<HtmlHelper, string, string, object, object, IAzOperation, MvcHtmlString> genMethod = ActionLink<HiddenUIBehavior>;
            MethodInfo method = genMethod.Method.GetGenericMethodDefinition();
            MethodInfo generic = method.MakeGenericMethod(new[] { AzMan.Defaults.UI.DenyiedBehavior });
            return generic.Invoke(htmlHelper, new[] { htmlHelper, linkText, actionName, routeValues, htmlAttributes, operation }) as MvcHtmlString;
        }

        public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, RouteValueDictionary routeValues, IAzOperation operation)
        {
            Func<HtmlHelper, string, string, RouteValueDictionary, IAzOperation, MvcHtmlString> genMethod = ActionLink<HiddenUIBehavior>;
            MethodInfo method = genMethod.Method.GetGenericMethodDefinition();
            MethodInfo generic = method.MakeGenericMethod(new[] { AzMan.Defaults.UI.DenyiedBehavior });
            return generic.Invoke(htmlHelper, new object[] { htmlHelper, linkText, actionName, routeValues, operation }) as MvcHtmlString;
        }

        public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes, IAzOperation operation)
        {
            Func<HtmlHelper, string, string, RouteValueDictionary, IDictionary<string, object>, IAzOperation, MvcHtmlString> genMethod = ActionLink<HiddenUIBehavior>;
            MethodInfo method = genMethod.Method.GetGenericMethodDefinition();
            MethodInfo generic = method.MakeGenericMethod(new[] { AzMan.Defaults.UI.DenyiedBehavior });
            return generic.Invoke(htmlHelper, new object[] { htmlHelper, linkText, actionName, routeValues, htmlAttributes, operation }) as MvcHtmlString;
        }

        public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName, IAzOperation operation)
        {
            Func<HtmlHelper, string, string, string, IAzOperation, MvcHtmlString> genMethod = ActionLink<HiddenUIBehavior>;
            MethodInfo method = genMethod.Method.GetGenericMethodDefinition();
            MethodInfo generic = method.MakeGenericMethod(new[] { AzMan.Defaults.UI.DenyiedBehavior });
            return generic.Invoke(htmlHelper, new object[] { htmlHelper, linkText, actionName, controllerName, operation }) as MvcHtmlString;
        }

        public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName, object routeValues, object htmlAttributes, IAzOperation operation)
        {
            Func<HtmlHelper, string, string, string, object, object, IAzOperation, MvcHtmlString> genMethod = ActionLink<HiddenUIBehavior>;
            MethodInfo method = genMethod.Method.GetGenericMethodDefinition();
            MethodInfo generic = method.MakeGenericMethod(new[] { AzMan.Defaults.UI.DenyiedBehavior });
            return generic.Invoke(htmlHelper, new [] { htmlHelper, linkText, actionName, controllerName, routeValues, htmlAttributes, operation }) as MvcHtmlString;
        }

        public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName, string protocol, string hostName, string fragment, object routeValues, object htmlAttributes, IAzOperation operation)
        {
            Func<HtmlHelper, string, string, string, string, string, string, object, object, IAzOperation, MvcHtmlString> genMethod = ActionLink<HiddenUIBehavior>;
            MethodInfo method = genMethod.Method.GetGenericMethodDefinition();
            MethodInfo generic = method.MakeGenericMethod(new[] { AzMan.Defaults.UI.DenyiedBehavior });
            return generic.Invoke(htmlHelper, new[] { htmlHelper, linkText, actionName, controllerName, protocol, hostName, fragment, routeValues, htmlAttributes, operation }) as MvcHtmlString;
        }

        public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes, IAzOperation operation)
        {
            Func<HtmlHelper, string, string, string, RouteValueDictionary, IDictionary<string, object>, IAzOperation, MvcHtmlString> genMethod = ActionLink<HiddenUIBehavior>;
            MethodInfo method = genMethod.Method.GetGenericMethodDefinition();
            MethodInfo generic = method.MakeGenericMethod(new[] { AzMan.Defaults.UI.DenyiedBehavior });
            return generic.Invoke(htmlHelper, new object[] { htmlHelper, linkText, actionName, controllerName, routeValues, htmlAttributes, operation }) as MvcHtmlString;
        }

        public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName, string protocol, string hostName, string fragment, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes, IAzOperation operation)
        {
            Func<HtmlHelper, string, string, string, string, string, string, RouteValueDictionary, IDictionary<string, object>, IAzOperation, MvcHtmlString> genMethod = ActionLink<HiddenUIBehavior>;
            MethodInfo method = genMethod.Method.GetGenericMethodDefinition();
            MethodInfo generic = method.MakeGenericMethod(new[] { AzMan.Defaults.UI.DenyiedBehavior });
            return generic.Invoke(htmlHelper, new object[] { htmlHelper, linkText, actionName, controllerName, protocol, hostName, fragment, routeValues, htmlAttributes, operation }) as MvcHtmlString;
        }

        /* 
         * Generic methods, thus you can provide an inhibition behavior.
         */
        public static MvcHtmlString ActionLink<TBehavior>(this HtmlHelper htmlHelper, string linkText, string actionName, IAzOperation operation)
            where TBehavior : IUIBehavior, new()
        {
            return ActionLink<TBehavior>(htmlHelper, linkText, actionName, null /* controllerName */, new RouteValueDictionary(), new RouteValueDictionary(), operation);
        }

        public static MvcHtmlString ActionLink<TBehavior>(this HtmlHelper htmlHelper, string linkText, string actionName, object routeValues, IAzOperation operation)
            where TBehavior : IUIBehavior, new()
        {
            return ActionLink<TBehavior>(htmlHelper, linkText, actionName, null /* controllerName */, new RouteValueDictionary(routeValues), new RouteValueDictionary(), operation);
        }

        public static MvcHtmlString ActionLink<TBehavior>(this HtmlHelper htmlHelper, string linkText, string actionName, object routeValues, object htmlAttributes, IAzOperation operation)
            where TBehavior : IUIBehavior, new()
        {
            return ActionLink<TBehavior>(htmlHelper, linkText, actionName, null /* controllerName */, new RouteValueDictionary(routeValues), HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes), operation);
        }

        public static MvcHtmlString ActionLink<TBehavior>(this HtmlHelper htmlHelper, string linkText, string actionName, RouteValueDictionary routeValues, IAzOperation operation)
            where TBehavior : IUIBehavior, new()
        {
            return ActionLink<TBehavior>(htmlHelper, linkText, actionName, null /* controllerName */, routeValues, new RouteValueDictionary(), operation);
        }

        public static MvcHtmlString ActionLink<TBehavior>(this HtmlHelper htmlHelper, string linkText, string actionName, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes, IAzOperation operation)
            where TBehavior : IUIBehavior, new()
        {
            return ActionLink<TBehavior>(htmlHelper, linkText, actionName, null /* controllerName */, routeValues, htmlAttributes, operation);
        }

        public static MvcHtmlString ActionLink<TBehavior>(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName, IAzOperation operation)
            where TBehavior : IUIBehavior, new()
        {
            return ActionLink<TBehavior>(htmlHelper, linkText, actionName, controllerName, new RouteValueDictionary(), new RouteValueDictionary(), operation);
        }

        public static MvcHtmlString ActionLink<TBehavior>(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName, object routeValues, object htmlAttributes, IAzOperation operation)
            where TBehavior : IUIBehavior, new()
        {
            return ActionLink<TBehavior>(htmlHelper, linkText, actionName, controllerName, new RouteValueDictionary(routeValues), HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes), operation);
        }

        public static MvcHtmlString ActionLink<TBehavior>(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName, string protocol, string hostName, string fragment, object routeValues, object htmlAttributes, IAzOperation operation)
            where TBehavior : IUIBehavior, new()
        {
            return ActionLink<TBehavior>(htmlHelper, linkText, actionName, controllerName, protocol, hostName, fragment, new RouteValueDictionary(routeValues), HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes), operation);
        }

        public static MvcHtmlString ActionLink<TBehavior>(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes, IAzOperation operation)
            where TBehavior : IUIBehavior, new()
        {
            TBehavior behavior = new TBehavior();

            if (!HttpContext.Current.User.Can(operation))
            {
                if (!behavior.ShouldRender)
                    return MvcHtmlString.Empty;
                return htmlHelper.ActionLink(linkText, actionName, controllerName, routeValues, behavior.GetHtmlAttributes(htmlAttributes));
            }
            return htmlHelper.ActionLink(linkText, actionName, controllerName, routeValues, htmlAttributes);
        }

        public static MvcHtmlString ActionLink<TBehavior>(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName, string protocol, string hostName, string fragment, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes, IAzOperation operation)
            where TBehavior : IUIBehavior, new()
        {
            TBehavior behavior = new TBehavior();

            if (!HttpContext.Current.User.Can(operation))
            {
                if (!behavior.ShouldRender)
                    return MvcHtmlString.Empty;
                htmlHelper.ActionLink(linkText, actionName, controllerName, protocol, hostName, fragment, routeValues, behavior.GetHtmlAttributes(htmlAttributes));
            }
            return htmlHelper.ActionLink(linkText, actionName, controllerName, protocol, hostName, fragment, routeValues, htmlAttributes);
        } 
    }
}